#include "ImageDecoder.h"
#include "WONCommon/WONFile.h"

using namespace WONAPI;
using namespace std;

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ImageAttributes::ImageAttributes()
{
	mWidth = mHeight = 0;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ImageDecoder::ImageDecoder()
{
	mFileReader = NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ImageDecoder::~ImageDecoder()
{
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage32Ptr ImageDecoder::CreateRawImage32(int theWidth, int theHeight)
{
	return Window::GetDefaultWindow()->GetDisplayContext()->CreateRawImage32(theWidth,theHeight);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImage8Ptr ImageDecoder::CreateRawImage8(int theWidth, int theHeight, Palette *thePalette)
{
	return Window::GetDefaultWindow()->GetDisplayContext()->CreateRawImage8(theWidth,theHeight,thePalette);
}


///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr ImageDecoder::DoDecode(DisplayContext *theContext)
{
	RawImagePtr anImage = DoDecodeRaw();
	
	if(anImage.get()!=NULL)
		return anImage->GetNative(theContext);
	else
		return NULL;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr ImageDecoder::Decode(DisplayContext *theContext, const char *theFilePath)
{
	FileReader aReader(theFilePath);
	return Decode(theContext, aReader);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr ImageDecoder::Decode(DisplayContext *theContext, const void *theData, unsigned long theDataLen)
{
	FileReader aReader(theData,theDataLen);
	return Decode(theContext, aReader);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr ImageDecoder::Decode(DisplayContext *theContext, FileReader &theReader)
{
	if(!theReader.IsOpen())
		return NULL;

	mFileReader = &theReader;
	return DoDecode(theContext);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImagePtr ImageDecoder::DecodeRaw(const char *theFilePath)
{
	FileReader aReader(theFilePath);
	return DecodeRaw(aReader);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImagePtr ImageDecoder::DecodeRaw(const void *theData, unsigned long theDataLen)
{
	FileReader aReader(theData,theDataLen);
	return DecodeRaw(aReader);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImagePtr ImageDecoder::DecodeRaw(FileReader &theReader)
{
	if(!theReader.IsOpen())
		return NULL;

	mFileReader = &theReader;

	try
	{
		return DoDecodeRaw();
	}
	catch(FileReaderException&)
	{
	}

	return false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool ImageDecoder::GetImageAttributes(const char *theFilePath, ImageAttributes &theAttrib)
{
	FileReader aReader(theFilePath);
	return GetImageAttributes(aReader,theAttrib);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool ImageDecoder::GetImageAttributes(const void *theData, unsigned long theDataLen, ImageAttributes &theAttrib)
{
	FileReader aReader(theData,theDataLen);
	return GetImageAttributes(aReader,theAttrib);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool ImageDecoder::GetImageAttributes(FileReader &theReader, ImageAttributes &theAttrib)
{
	if(!theReader.IsOpen())
		return false;

	mFileReader = &theReader;
	try
	{
		return DoGetAttrib(theAttrib);
	}
	catch(FileReaderException&)
	{
	}

	return false;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
MultiImageDecoder::MultiImageDecoder()
{
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
MultiImageDecoder::~MultiImageDecoder()
{
	DecoderSet::iterator anItr = mDecoderSet.begin();
	while(anItr!=mDecoderSet.end())
	{
		delete *anItr;
		++anItr;
	}


}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void MultiImageDecoder::AddDecoder(ImageDecoder *theDecoder, const char *theExtension)
{
	if(!mDecoderMap.insert(DecoderMap::value_type(theExtension,theDecoder)).second)
		delete theDecoder;
	else
		mDecoderSet.insert(theDecoder);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
void MultiImageDecoder::SetFileName(const char *theFileName)
{
	WONFile aFile(theFileName);
	SetCurExtension(aFile.GetFileExtension().c_str());
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr MultiImageDecoder::Decode(DisplayContext *theContext, const char *theFilePath)
{
	SetFileName(theFilePath);
	return ImageDecoder::Decode(theContext,theFilePath);

}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImagePtr MultiImageDecoder::DecodeRaw(const char *theFilePath)
{
	SetFileName(theFilePath);
	return ImageDecoder::DecodeRaw(theFilePath);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool MultiImageDecoder::GetImageAttributes(const char *theFilePath, ImageAttributes &theAttrib)
{
	SetFileName(theFilePath);
	return ImageDecoder::GetImageAttributes(theFilePath,theAttrib);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
NativeImagePtr MultiImageDecoder::DoDecode(DisplayContext *theContext)
{
	mAnimation = NULL;

	DecoderMap::iterator anItr = mDecoderMap.find(mCurExtension);
	if(anItr==mDecoderMap.end())
		return NULL;

	ImageDecoder *aDecoder = anItr->second;
	NativeImagePtr anImage = aDecoder->Decode(theContext,*mFileReader);
	if(anImage.get()!=NULL)
		mAnimation = aDecoder->GetAnimation();

	return anImage;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
RawImagePtr MultiImageDecoder::DoDecodeRaw()
{
	mAnimation = NULL;

	DecoderMap::iterator anItr = mDecoderMap.find(mCurExtension);
	if(anItr==mDecoderMap.end())
		return NULL;

	ImageDecoder *aDecoder = anItr->second;
	RawImagePtr anImage = aDecoder->DecodeRaw(*mFileReader);
	if(anImage.get()!=NULL)
		mAnimation = aDecoder->GetAnimation();

	return anImage;
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
bool MultiImageDecoder::DoGetAttrib(ImageAttributes &theAttrib)
{
	DecoderMap::iterator anItr = mDecoderMap.find(mCurExtension);
	if(anItr==mDecoderMap.end())
		return NULL;

	ImageDecoder *aDecoder = anItr->second;
	return aDecoder->GetImageAttributes(*mFileReader,theAttrib);
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
AnimationPtr MultiImageDecoder::GetAnimation(bool evenIfOnlyOneFrame)
{
	if(evenIfOnlyOneFrame)
		return mAnimation;
	else
	{
		if(mAnimation.get()==NULL || mAnimation->GetNumFrames()<=1)
			return NULL;
		else
			return mAnimation;
	}
}

///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
ImageDecoder* MultiImageDecoder::Duplicate()
{
	MultiImageDecoder *aDecoder = new MultiImageDecoder;
	aDecoder->mDecoderMap = mDecoderMap;

	DecoderMap::iterator anItr = aDecoder->mDecoderMap.begin();
	while(anItr!=aDecoder->mDecoderMap.end())
	{
		anItr->second = anItr->second->Duplicate();
		aDecoder->mDecoderSet.insert(anItr->second);

		++anItr;
	}

	return aDecoder;
}
